package com.chens.common.security;

import com.chens.common.filter.JwtAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * SpringSecurity配置类
 * @description 用于配置SpringSecurity的安全策略、认证方式、授权方式等
 * @author chensh
 * @date 2025/08/01 16:22
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SpringSecurityConfig {

    /**
     * 自定义用户详情服务
     */
    private final CustomUserDetailsService userDetailsService;
    /**
     * JWT工具类
     */
    private final JwtTokenUtils jwtTokenUtils;
    /**
     * 自定义认证失败处理器
     */
    private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
    /**
     * 自定义授权失败处理器
     */
    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    @Autowired
    public SpringSecurityConfig(CustomUserDetailsService userDetailsService, JwtTokenUtils jwtTokenUtils, CustomAuthenticationEntryPoint customAuthenticationEntryPoint, CustomAccessDeniedHandler customAccessDeniedHandler) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtils = jwtTokenUtils;
        this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
        this.customAccessDeniedHandler = customAccessDeniedHandler;
    }

    /**
     * 密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    /**
     * 认证管理器
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }


    /**
     * Security 配置安全过滤链
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 由于使用的是JWT，我们这里不需要csrf
        http.csrf(csrf -> csrf.disable());

        // 禁用session
        http.sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        // 添加自定义未授权和未登录结果返回
        http.exceptionHandling(customizer  -> customizer
                // 处理未登录
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                // 处理未授权
                .accessDeniedHandler(customAccessDeniedHandler));

        // 配置请求授权
        http.authorizeHttpRequests(auth -> auth
                .requestMatchers("/sys/auth/login").permitAll()
                .requestMatchers("/uploads/**").permitAll()
                .anyRequest().authenticated()
            );

        // 添加认证提供者
        // http.authenticationProvider(authenticationProvider());

        // 添加JWT认证过滤器，在Jwt过滤器中获取认证信息，然后将认证信息设置到SecurityContextHolder中
        http.addFilterBefore(new JwtAuthenticationFilter(jwtTokenUtils, userDetailsService)
                ,UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}